#!/usr/bin/env python
# -*- coding: utf8 -*-
import sys
import os

from Bio import SeqIO, SeqUtils, AlignIO
from Bio.Align.Applications import ClustalwCommandline
from Bio.SeqRecord import SeqRecord


def calc_gc(record):
    return SeqUtils.GC(record.seq)


def transcribe_record(record):
    return record.seq.transcribe()


def translate_record(record):
    return record.seq.translate()


def show_gc(records):
    print '========== GC info block =========='
    for record in records:
        print '{}: {}'.format(record.id, calc_gc(record))


def show_transcribe(records):
    print '========= Transcribe block ========'
    for record in records:
        print '{}: {}\n'.format(record.id, transcribe_record(record))


def show_translation(records):
    print '======== Translation block ========'
    for record in records:
        print '{}: {}\n'.format(record.id, translate_record(record))


def show_align(records, align_dump_filename):
    print '========= Alignment block ========='
    for align in mult_align(records, align_dump_filename):
        for seq in align:
            print 'id: {}:\n{}'.format(seq.id, seq.seq)


def mult_align(records, align_file):
    in_filename = '__align_proteins.tmp.fa'
    align_tmp_file = in_filename[:-2] + 'dnd'
    out_filename = '__align_result.tmp.aln'

    with open(in_filename, 'w') as handle:
        proteins = (SeqRecord(seq=record.seq.translate(), id=str(i) + record.id)
                    for i, record in enumerate(records))
        SeqIO.write(proteins, handle, 'fasta')

    aligner = ClustalwCommandline('clustalw', infile=in_filename, matrix='BLOSUM', outfile=out_filename)
    aligner()

    with open(out_filename) as handle:
        alignment = list(AlignIO.parse(handle, 'clustal'))
    with open(align_file, 'w') as out_align_handle:
        AlignIO.write(alignment, out_align_handle, 'phylip')

    os.remove(in_filename)
    os.remove(align_tmp_file)
    os.remove(out_filename)

    return alignment


def get_file_format(filename):
    if filename.endswith('.fasta') or filename.endswith('.fa'):
        return 'fasta'
    elif filename.endswith('.gb') or filename.endswith('.gbk'):
        return 'genbank'
    else:
        raise Exception('Unknown file format')


def get_file_records(filename):
    with open(filename) as handle:
        return list(SeqIO.parse(handle, get_file_format(filename)))


def is_valid_file(filename):
    return os.path.exists(filename) and os.path.isfile(filename)


def load_records(filenames):
    records = []
    for filename in filenames:
        if not is_valid_file(filename):
            sys.stderr.write(filename + ' is not a valid file\n')
            continue
        try:
            file_records = get_file_records(filename)
        except Exception as e:
            sys.stderr.write(e.message + '; skip the file ' + filename + '\n')
            continue

        records.extend(file_records)
    return records


def process_records(records):
    show_gc(records)
    show_transcribe(records)
    show_translation(records)
    show_align(records, 'align.phy')


def main():
    if len(sys.argv) < 2:
        sys.stderr.write('Usage: ' + sys.argv[0] + ' <files>...\n')
        exit(1)

    filenames = sys.argv[1:]
    records = load_records(filenames)
    process_records(records)


if __name__ == '__main__':
    main()
